﻿namespace USElections.TwitterLibrary
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Net;
    using System.Runtime.Serialization.Json;
    using AgFx;
    using TweetSharp;
    using USElections.TwitterLibrary.Classes;

    /// <summary>
    /// RssFeed class.
    /// </summary>
    [CachePolicy(CachePolicy.CacheThenRefresh, 60 * 5)] // five minutes.
    public class TwitterFeed : ModelItemBase<TwitterLoadContext>
    {
        #region Fields
        private string twittername;
        private ObservableCollection<Tweet> timeline = new ObservableCollection<Tweet>();
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the TwitterFeed class.
        /// </summary>
        public TwitterFeed()
        {
        }

        /// <summary>
        /// Initializes a new instance of the TwitterFeed class.
        /// </summary>
        /// <param name="twittername">The Twitter name.</param>
        public TwitterFeed(string twittername)
            : base(new TwitterLoadContext(twittername))
        {
            this.TwitterName = twittername;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the Twitter name.
        /// </summary>
        public string TwitterName
        {
            get
            {
                return this.twittername;
            }

            set
            {
                this.twittername = value;
                RaisePropertyChanged("TwitterName");
            }
        }

        /// <summary>
        /// Gets or sets the user TimeLine.
        /// </summary>
        public ObservableCollection<Tweet> TimeLine
        {
            get
            {
                return this.timeline;
            }

            set
            {
                this.timeline = value;
                RaisePropertyChanged("TimeLine");
            }
        }
        #endregion

        #region Internal classes
        /// <summary>
        /// VotesDataLoader class.
        /// </summary>
        public class TwitterDataLoader : IDataLoader<TwitterLoadContext>
        {
            #region Public methods
            public object Deserialize(TwitterLoadContext loadContext, Type objectType, System.IO.Stream stream)
            {
                IEnumerable<TwitterStatus> obj = null;

                MemoryStream ms = stream as MemoryStream;

                if (ms != null)
                {
                    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(IEnumerable<TwitterStatus>));
                    obj = (IEnumerable<TwitterStatus>)ser.ReadObject(ms);
                    ms.Close();
                }

                TwitterFeed feed = new TwitterFeed(loadContext.TwitterName);

                if (obj != null)
                {
                    TwitterService ts = new TwitterService();

                    foreach (var status in obj)
                    {
                        TwitterStatus completeStatus = ts.Deserialize<TwitterStatus>(status.RawSource);
                        Tweet tweet = new Tweet(completeStatus);
                        feed.TimeLine.Add(tweet);
                    }
                }

                return feed;
            }

            public LoadRequest GetLoadRequest(TwitterLoadContext loadContext, Type objectType)
            {
                return new TwitterLoadRequest(loadContext, loadContext.TwitterName);
            }
            #endregion
        }

        /// <summary>
        /// TwitterLoadRequest class.
        /// </summary>
        public class TwitterLoadRequest : LoadRequest
        {
            private const string Consumerkey = "__your consumer key__";
            private const string Consumersecret = "__your consumer secret__";
            private string twittername;
            private TwitterService twitterService = null;

            /// <summary>
            /// Initializes a new instance of the TwitterLoadRequest class.
            /// </summary>
            /// <param name="loadContext">The LoadContext.</param>
            /// <param name="twittername">The Twitter name.</param>
            public TwitterLoadRequest(TwitterLoadContext loadContext, string twittername)
                : base(loadContext)
            {
                this.twittername = twittername;
            }

            public override void Execute(Action<LoadRequestResult> result)
            {
                if (result == null)
                {
                    throw new ArgumentNullException();
                }

                try
                {
                    this.twitterService = new TwitterService(Consumerkey, Consumersecret);
                    this.twitterService.ListTweetsOnSpecifiedUserTimeline(
                        this.twittername,
                        (statuses, response) =>
                        {
                            try
                            {
                                if (response.StatusCode == HttpStatusCode.OK)
                                {
                                    // Have to clear this, unable to serialize.
                                    foreach (var status in statuses)
                                    {
                                        status.Entities = null;
                                    }

                                    MemoryStream ms = new MemoryStream();
                                    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(IEnumerable<TwitterStatus>));
                                    ser.WriteObject(ms, statuses);
                                    byte[] data = ms.ToArray();
                                    ms.Close();

                                    result(new LoadRequestResult(new MemoryStream(data)));
                                }
                                else
                                {
                                    result(new LoadRequestResult(new WebException("Bad web response, StatusCode=" + response.StatusCode)));
                                }
                            }
                            catch
                            {
                                result(new LoadRequestResult(new Exception("Failed to load")));
                            }
                        });
                }
                catch
                {
                    result(new LoadRequestResult(new Exception("Failed to load")));
                }
            }
        }
        #endregion
    }
}